package com.tqyan.service.transfer;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.PutObjectResult;
import com.tqyan.model.exp.DefaultException;
import com.tqyan.util.GuidUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.InputStreamSource;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;

/**
 * 文件服务
 * <p> <功能详细描述> </p>
 *
 * @author 陈晨
 * @version 1.0
 * @date 2023/4/14
 */
@Component
@Slf4j
public class FileService {
    private static final String ACCESS_KEY_ID = "LTAI5tSdGbUgYdzUR3aK7Xot";
    private static final String ACCESS_KEY_SECRET = "e7YQCwKWMJ2XZB0Je4gvpQv0xdd0R2";
//    private static final String ENDPOINT = "http://oss-us-west-1.aliyuncs.com";
//    private static final String BUCKET = "chatgpt009";
    private static final String ENDPOINT = "http://oss-cn-hangzhou.aliyuncs.com";
    private static final String BUCKET = "chatgpt008";

    public static final String FOLDER_DRAW = "draw/";
    public static final String FOLDER_SHARE = "share/";
    public static final String FOLDER_PAPER = "paper/";
    public static final String FOLDER_NOVEL = "novel/";
    public static final String FOLDER_ORIGINAL = "original/";
    public static final String FOLDER_THUMBNAIL = "thumbnail/";
    public static final String FOLDER_DRAW_ORIGINAL = FOLDER_DRAW + FOLDER_ORIGINAL;
    public static final String FOLDER_DRAW_THUMBNAIL = FOLDER_DRAW + FOLDER_THUMBNAIL;
    public static final String FOLDER_SHARE_ORIGINAL = FOLDER_SHARE + FOLDER_ORIGINAL;
    public static final String FOLDER_SHARE_THUMBNAIL = FOLDER_SHARE + FOLDER_THUMBNAIL;

    public static final String FOLDER_LOCAL_TEMP = "/data/app/temp/";
    public static final String FOLDER_LOCAL_TEMP_CONVERT = FOLDER_LOCAL_TEMP + "convert/";

    /** Logo */
    public static File LOGO;
    /** 小程序码 */
    public static File MINI;
    /** 管理员微信 */
    public static File MANAGER;

    @PostConstruct
    public void init() {
        // logo
        String fileName = "logo.jpg";
        LOGO = new File(FOLDER_LOCAL_TEMP_CONVERT + fileName);
        if (!LOGO.exists()) {
            LOGO = this.downloadAliyunOSS(FOLDER_DRAW, fileName, false);
        }
        // 小程序码
        fileName = "mini_150.jpg";
        MINI = new File(FOLDER_LOCAL_TEMP_CONVERT + fileName);
        if (!MINI.exists()) {
            MINI = this.downloadAliyunOSS(FOLDER_SHARE + "tqyan/", fileName, false);
        }
        // 管理员微信
        fileName = "manager_150.jpeg";
        MANAGER = new File(FOLDER_LOCAL_TEMP_CONVERT + fileName);
        if (!MANAGER.exists()) {
            MANAGER = this.downloadAliyunOSS(FOLDER_SHARE + "tqyan/", fileName, false);
        }
    }

    /**
     * @description 文件删除
     * <p> <功能详细描述> </p>
     *
     * @author 陈晨
     * @date 2023/4/18 00:42
     */
    public void delete(File file) {
        if (null != file && file.exists()) {
            file.delete();
        }
    }

    /**
     * @description 随机文件名
     * <p> <功能详细描述> </p>
     *
     * @author 陈晨
     * @date 2023/4/18 01:22
     */
    public String randomFileName(String fileName) {
        return GuidUtil.getUUID() + fileName.substring(fileName.indexOf("."));
    }

    /**
     * @description 文件添加水印, 上传阿里云
     * <p> <功能详细描述> </p>
     *
     * @author 陈晨
     * @date 2023/4/18 01:39
     */
    public void uploadAliyunOSS(File file, String folder, double rate) {
        // 绘制缩略图
        File thumbnail = this.imageCompression(file, 256, 1, rate);
        log.info("[文件服务] fileName={}, 绘制缩略图", file.getName());
//        // 原图、缩略图添加水印
//        File fileWatermark = this.imageWatermark(file, LOGO);
//        log.info("[文件服务] fileName={}, 原图, 添加水印", file.getName());
//        File thumbnailWatermark = this.imageWatermark(thumbnail, LOGO);
//        log.info("[文件服务] fileName={}, 缩略图, 添加水印", file.getName());
        // 上传阿里云
        this.uploadAliyunOSS(file, folder + FOLDER_ORIGINAL, file.getName());
        log.info("[文件服务] fileName={}, 原图, 上传阿里云", file.getName());
        this.uploadAliyunOSS(thumbnail, folder + FOLDER_THUMBNAIL, file.getName());
        log.info("[文件服务] fileName={}, 缩略图, 上传阿里云", file.getName());
        // 文件删除
        thumbnail.delete();
//        fileWatermark.delete();
//        thumbnailWatermark.delete();
        log.info("[文件服务] fileName={}, 本地图片删除", file.getName());
    }
    public void uploadAliyunOSS(File file, String folder) {
        this.uploadAliyunOSS(file, folder, 1);
    }

    /**
     * @description 下载文件, 添加水印, 上传阿里云
     * <p> <功能详细描述> </p>
     *
     * @author 陈晨
     * @date 2023/4/18 02:03
     */
    public void downloadAndUploadAliyunOSS(String url, String folder, String fileName, double rate) {
        File file = this.download(url, fileName);
        log.info("[文件服务] fileName={}, 下载生成图片", fileName);
        this.uploadAliyunOSS(file, folder, rate);
        file.delete();
    }
    public void downloadAndUploadAliyunOSS(String url, String folder, String fileName) {
        this.downloadAndUploadAliyunOSS(url, folder, fileName, 1);
    }

    /**
     * @description 文件上传阿里云OSS
     * <p> <功能详细描述> </p>
     *
     * @author 陈晨
     * @date 2023/4/14 14:53
     */
    public void uploadAliyunOSS(InputStream file, String folder, String fileName) {
        OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);
        try {
            PutObjectResult putResult = ossClient.putObject(BUCKET, folder + fileName, file);
//            log.info("[文件上传] putResult={}", JSONObject.toJSONString(putResult));
        } catch (Exception e) {
            log.error("[文件上传] 文件上传阿里云OSS异常: {}", e.getMessage(), e);
            throw new DefaultException(e.getMessage());
        } finally {
            if (null != file) {
                try {
                    file.close();
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }
            }
            ossClient.shutdown();
        }
    }
    public void uploadAliyunOSS(File file, String folder, String fileName) {
        OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);
        try {
            PutObjectResult putResult = ossClient.putObject(BUCKET, folder + fileName, file);
//            log.info("[文件上传] putResult={}", JSONObject.toJSONString(putResult));
        } catch (Exception e) {
            log.error("[文件上传] 文件上传阿里云OSS异常: {}", e.getMessage(), e);
            throw new DefaultException(e.getMessage());
        } finally {
            ossClient.shutdown();
        }
    }

    /**
     * @description 阿里云OSS文件下载
     * <p> <功能详细描述> </p>
     *
     * @author 陈晨
     * @date 2023/4/14 15:37
     */
    public void downloadAliyunOSS(OutputStream output, String folder, String fileName) {
        OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);
        InputStream reader = null;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            OSSObject ossObject = ossClient.getObject(BUCKET, folder + fileName);
            reader = ossObject.getObjectContent();
            int ch;
            while ((ch = reader.read()) != -1) {
                baos.write(ch);
            }
            output.write(baos.toByteArray());
        } catch (Exception e) {
            log.error("[文件下载] 阿里云OSS文件下载异常: {}", e.getMessage(), e);
            throw new DefaultException(e.getMessage());
        } finally {
            try {
                baos.close();
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
            if (null != reader) {
                try {
                    reader.close();
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }
            }
            ossClient.shutdown();
        }
    }
    public File downloadAliyunOSS(String folder, String fileName, boolean rename) {
        OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);
        InputStream reader = null;
        FileOutputStream output = null;
        File file = new File(FOLDER_LOCAL_TEMP_CONVERT + (rename ? this.randomFileName(fileName) : fileName));
        try {
            OSSObject ossObject = ossClient.getObject(BUCKET, folder + fileName);
            reader = ossObject.getObjectContent();
            output = new FileOutputStream(file);
            int ch;
            while ((ch = reader.read()) != -1) {
                output.write(ch);
            }
            return file;
        } catch (Exception e) {
            log.error("[文件下载] 阿里云OSS文件下载异常: {}", e.getMessage(), e);
            throw new DefaultException(e.getMessage());
        } finally {
            if (null != output) {
                try {
                    output.close();
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }
            }
            if (null != reader) {
                try {
                    reader.close();
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }
            }
            ossClient.shutdown();
        }
    }

    /**
     * @description 阿里云图片压缩
     * <p> <功能详细描述> </p>
     *
     * @author 陈晨
     * @date 2023/4/14 23:38
     */
    public void imageCompressionAliyunOSS(String fileName, String sourceFolder, String targetFolder) {
        // 下载OSS图片
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        InputStreamSource inputSource = null;
        BufferedInputStream input = null;
        ByteArrayOutputStream thumbnailOutput = new ByteArrayOutputStream();
        try {
            this.downloadAliyunOSS(output, sourceFolder, fileName);
            // 转输出流
            inputSource = new ByteArrayResource(output.toByteArray());
            input = new BufferedInputStream(inputSource.getInputStream());
            this.imageCompression(input, 256, 256, thumbnailOutput);
        } catch (Exception e) {
            log.error("[图片压缩] 阿里云图片压缩异常: {}", e.getMessage(), e);
            throw new DefaultException(e.getMessage());
        } finally {
            try {
                output.close();
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
            try {
                if (null != inputSource) {
                    inputSource.getInputStream().close();
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
            try {
                if (null != input) {
                    input.close();
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }
        // 缩略图上传OSS
        inputSource = null;
        input = null;
        try {
            inputSource = new ByteArrayResource(thumbnailOutput.toByteArray());
            input = new BufferedInputStream(inputSource.getInputStream());
            this.uploadAliyunOSS(input, targetFolder, fileName);
        } catch (Exception e) {
            log.error("[图片压缩] 阿里云图片压缩异常: {}", e.getMessage(), e);
            throw new DefaultException(e.getMessage());
        } finally {
            try {
                if (null != input) {
                    input.close();
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
            try {
                if (null != inputSource) {
                    inputSource.getInputStream().close();
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
            try {
                thumbnailOutput.close();
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }
    }

    /**
     * @description 下载文件, 获取文件流
     * <p> <功能详细描述> </p>
     *
     * @author 陈晨
     * @date 2023/4/14 15:04
     */
    public InputStream download(String url) {
        try {
            URLConnection connection = new URL(url).openConnection();
            connection.setConnectTimeout(30 * 1000);
            return connection.getInputStream();
        } catch (Exception e) {
            log.error("[文件下载] 获取文件流异常: {}", e.getMessage(), e);
            throw new DefaultException(e.getMessage());
        }
    }
    public File download(String url, String fileName) {
        InputStream reader = null;
        FileOutputStream output = null;
        File file = new File(FOLDER_LOCAL_TEMP + fileName);
        try {
            URLConnection connection = new URL(url).openConnection();
            connection.setConnectTimeout(30 * 1000);
            reader = connection.getInputStream();
            output = new FileOutputStream(file);
            int ch;
            while ((ch = reader.read()) != -1) {
                output.write(ch);
            }
            return file;
        } catch (Exception e) {
            log.error("[文件下载] 文件下载异常: {}", e.getMessage(), e);
            throw new DefaultException(e.getMessage());
        } finally {
            if (null != output) {
                try {
                    output.close();
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }
            }
            if (null != reader) {
                try {
                    reader.close();
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }
            }
        }
    }

    /**
     * @description 上传文件转 文件输入流
     * <p> <功能详细描述> </p>
     *
     * @author 陈晨
     * @date 2023/4/15 19:11
     */
    public FileInputStream convertUploadFile(MultipartFile file) {
        File convertFile = null;
        try {
            convertFile = new File(FOLDER_LOCAL_TEMP_CONVERT + file.getOriginalFilename());
            FileUtils.copyInputStreamToFile(file.getInputStream(), convertFile);
            return new FileInputStream(convertFile);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return null;
        } finally {
            if (null != convertFile && convertFile.exists()) {
                convertFile.delete();
            }
        }
    }

    /**
     * @description 图片压缩
     * <p> <功能详细描述> </p>
     *
     * @author 陈晨
     * @date 2023/4/14 22:39
     */
    public void imageCompression(InputStream input, int width, int height, ByteArrayOutputStream output) {
        try {
            Image src = ImageIO.read(input);
            BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            image.getGraphics().drawImage(src.getScaledInstance(width, height, Image.SCALE_SMOOTH), 0, 0, null);
            ImageIO.write(image, "png", output);
        } catch (Exception e) {
            log.error("[图片压缩] 异常: {}", e.getMessage(), e);
            throw new DefaultException(e.getMessage());
        }
    }
    public File imageCompression(File file, int size, int direction, double rate) {
        try {
            // 读取原图
            BufferedImage src = ImageIO.read(file);
            // 计算压缩图
            int width = size;
            int height = size;
            rate = rate > 1 ? 1 : rate;
            if (direction == 0) {
                width *= rate;
            } else {
                height *= rate;
            }
            // 绘制缩略图
            BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            image.getGraphics().drawImage(src.getScaledInstance(size, size, Image.SCALE_SMOOTH)
                    , width / 2 - size / 2
                    , height / 2 - size / 2
                    , null);
            File targetFile = new File(FOLDER_LOCAL_TEMP + this.randomFileName(file.getName()));
            ImageIO.write(image, "png", targetFile);
            return targetFile;
        } catch (Exception e) {
            log.error("[图片压缩] 异常: {}", e.getMessage(), e);
            throw new DefaultException(e.getMessage());
        }
    }

    /**
     * @description 图片添加水印
     * <p> <功能详细描述> </p>
     *
     * @author 陈晨
     * @date 2023/4/14 22:39
     */
    public File imageWatermark(File file, File watermark) {
        FileInputStream input = null;
        try {
            // 读取图片
            input = new FileInputStream(file);
            BufferedImage image = ImageIO.read(input);
            // 按比例绘制水印
            File thumbnail = this.imageCompression(watermark, Math.min(image.getWidth(), image.getHeight()) / 10, 0, 1);
            BufferedImage watermarkImage = ImageIO.read(thumbnail);
            // 计算合成后的图片大小和位置
            int x = image.getWidth() - watermarkImage.getWidth();
            int y = image.getHeight() - watermarkImage.getHeight();
            // 创建新的合成后的图片
            BufferedImage mergedImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
            // 合成第一张图片
            Graphics2D g2d = mergedImage.createGraphics();
            g2d.drawImage(image, 0, 0, null);
            // 合成第二张图片
            AlphaComposite alpha = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.8f);
            g2d.setComposite(alpha);
            g2d.drawImage(watermarkImage, x, y, null);
            // 保存合成后的图片
            File outputfile = new File(FOLDER_LOCAL_TEMP + this.randomFileName(file.getName()));
            ImageIO.write(mergedImage, "png", outputfile);
            // 删除水印
            thumbnail.delete();
            return outputfile;
        } catch (Exception e) {
            log.error("[图片合成] 异常: {}", e.getMessage(), e);
            throw new DefaultException(e.getMessage());
        } finally {
            if (null != input) {
                try {
                    input.close();
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }
            }
        }
    }

    public static void main(String[] args) throws Exception {
        FileService service = new FileService();
        service.init();
        // 图片上传阿里云
//        File temp = new File("/Users/chenchen/app/temp");
//        File[] images = temp.listFiles();
//        for (File file : images) {
//            if (!file.getName().contains(".png")) {
//                continue;
//            }
//            service.uploadAliyunOSS(file, FOLDER_SHARE, 0.8);
//            System.out.println(file.getName());
//        }

//        // 全流程测试
//        String url = "https://oaidalleapiprodscus.blob.core.windows.net/private/org-34fKcGR8UN2fEkwAPL9HJuWH/user-dj4j55J6yo0Sdb1ecC28u5To/img-nkwl5Mh1NkqEiXXllu8kOfSd.png?st=2023-04-17T18%3A14%3A25Z&se=2023-04-17T20%3A14%3A25Z&sp=r&sv=2021-08-06&sr=b&rscd=inline&rsct=image/png&skoid=6aaadede-4fb3-4698-a8f6-684d7786b067&sktid=a48cca56-e6da-484e-a814-9c849652bcb3&skt=2023-04-17T19%3A10%3A02Z&ske=2023-04-18T19%3A10%3A02Z&sks=b&skv=2021-08-06&sig=EW66WvbmST9fS6G5X6kRvbSC4rW%2BYLE2z0DSF6ifkUQ%3D";
//        String fileName = GuidUtil.getUUID() + ".png";
//        service.downloadAndUploadAliyunOSS(url, FOLDER_SHARE, fileName, 0.8);
//        // 下载阿里云文件
//        service.downloadAliyunOSS(FOLDER_SHARE_ORIGINAL, fileName);
//        service.downloadAliyunOSS(FOLDER_SHARE_THUMBNAIL, fileName);

        // OSS下载
        service.downloadAliyunOSS(FileService.FOLDER_SHARE_THUMBNAIL, "1.png", false);
    }

}


